const path = require("path")
const axios = require("axios");
const ora = require("ora");
const Inquirer = require("inquirer");
const {
    promisify
} = require("util")
let downLoadGitRepo = require("download-git-repo")
downLoadGitRepo = promisify(downLoadGitRepo)
let ncp = require("ncp")
ncp = promisify(ncp)
const fs = require("fs")
const MetalSmith = require("metalsmith")
let Handlebars = require("consolidate").handlebars
Handlebars = promisify(Handlebars)
const match = require("minimatch")
const {
    downloadDirectory
} = require("./constants")
const fetchList = async () => {
    // 
    // https://api.github.com/orgs/zhu-cli/repos
    // https://api.github.com/repos/td-cli/${repo}/tags
    const {
        data
    } = await axios.get("https://api.github.com/users/meet-you-123/repos")
    return data
}

const fetchTagsList = async (repo) => {
    const {
        data
    } = await axios.get(`https://api.github.com/repos/meet-you-123/${repo}/tags`)
    return data
}

const download = async (repo, tag) => {
    let api = `meet-you-123/${repo}`
    if (tag) {
        api += `#${tag}`
    }
    const dest = `${downloadDirectory}/${repo}`;
    await downLoadGitRepo(api, dest);
    return dest;
}

const waitFnLoading = (fn, message) => async (...args) => {
    const spinner = ora(message);
    spinner.start(); // 开始loading
    let res = await fn(...args)
    spinner.succeed() //结束loading
    return res
}
module.exports = async (proname) => {

    // 选择模板
    let res = await waitFnLoading(fetchList, 'fetch template.....')()

    res = res.map((item) => item.name)
    const {
        repo
    } = await Inquirer.prompt({
        name: "repo",
        type: "list",
        message: "please choose a template to  create project",
        choices: res,
    })

    // 选择版本号
    let tags = await waitFnLoading(fetchTagsList, "fetching tag......")(repo)

    tags = tags.map((item) => item.name)
    const {
        tag
    } = await Inquirer.prompt({
        name: "tag",
        type: "list",
        message: "please choose a template to create project",
        choices: tags
    })

    // 下载项目 返回一个临时的存放目录
    const result = await waitFnLoading(download, "downloading template....")(repo, tag)
    if (!fs.existsSync(path.join(result, "meta.js"))) {
        await ncp(result, path.resolve(proname))
    } else {
        // 复杂模板
        await new Promise((resolve, reject) => {
            MetalSmith(__dirname)
                .source(result) //遍历下载的目录
                .destination(path.resolve(proname)) //最终编译好的文件存放位置
                .use(async (files, metal, done) => {
                    const {
                        prompts,
                        filter
                    } = require(path.join(result, "meta.js"))
                    const obj = await Inquirer.prompt(prompts)
                    console.log(obj);
                    const meta = metal.metadata()
                    Object.assign(meta, obj) //将询问的结果放到metadata中保证在下一个中间件中可以获取到
                    delete files["meta.js"]
                    const fileNames = Object.keys(files)
                    Object.keys(filter).forEach(glob => {
                        glob = "tem/" + glob
                        fileNames.forEach(file => {
                            file = file.replace(/\\/g, "/");
                            if (match(file, glob, {
                                    dot: true
                                })) {
                                console.log('匹配文件');
                                glob = glob.replace("tem/", "")
                                file = file.replace(/\//g, "\\");
                                const condition = filter[glob];
                                if (!obj[condition]) {
                                    delete files[file];
                                }
                            }
                        })
                    })
                    done()
                })
                .use((files, metal, done) => {
                    const obj = metal.metadata()
                    Reflect.ownKeys(files).forEach(async (file) => {
                        if (file.includes(".json") || file.includes(".js") || file.includes(".ts") || file.includes(".vue")) {
                            let content = files[file].contents.toString()
                            if (content.includes("{{")) {
                                content = await Handlebars.render(content, obj)
                                files[file].contents = Buffer.from(content)
                            }
                        }
                    })
                    done()
                })
                .build(err => {
                    if (err) {
                        reject()
                    } else {
                        resolve()
                    }
                })
        })
    }
}